package org.sang.authentications.fliters;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.sang.pojo.CustomUser;
import org.sang.pojo.RespBean;
import org.sang.pojo.dto.RoleDTO;
import org.sang.service.UserService;
import org.sang.utils.JwtTokenUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class JwtAuthenticationFilter extends GenericFilterBean {
    private final static Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);

    private static final List<String> whiteRequestList = new ArrayList<>();

    private final UserService userService;

    public JwtAuthenticationFilter(UserService userService) {
        this.userService = userService;
    }

    static {
        whiteRequestList.add("/blog/user/login");
        whiteRequestList.add("/blog/user/reg");
        whiteRequestList.add("/blog/sendLoginVerifyCode");
        whiteRequestList.add("/blog/upload/user/avatar");
        whiteRequestList.add("/blog/error");
//        whiteRequestList.add("/blog/upload/ckEditor/simpleUploadAdapter");
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        if(HttpMethod.OPTIONS.name().equals(request.getMethod())){
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        logger.info("requestUrl:{}", request.getRequestURI());
        if(whiteRequestList.contains(request.getRequestURI()) || request.getRequestURI().endsWith(".css") || request.getRequestURI().equals(".js") ||
                request.getRequestURI().endsWith(".png") || request.getRequestURI().endsWith("favicon.ico")){
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        String AUTHORIZATION_NAME = "Authorization";
        String authToken = request.getHeader(AUTHORIZATION_NAME);
        if(StringUtils.isEmpty(authToken)){
            logger.info("requestUrl:{}", request.getRequestURI());
            String message = "user unauthorized";
            this.printException(response, HttpStatus.UNAUTHORIZED.value(), message);
            return;
        }
        Map<String, Object> verifyMap = JwtTokenUtil.verifyJwtToken(authToken);
        int authStatus = (int) verifyMap.get("status");
        if(authStatus==406){
            String message = "token超时";
            response.setStatus(406);
            this.printException(response, 406, message);
            return;
        }
        if(authStatus==401){
            String message = "无效的token";
            this.printException(response, 401, message);
            return;
        }
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String username = (String) verifyMap.get("username");
        if(authentication==null || authentication.getPrincipal()==null){
            CustomUser customUser = (CustomUser) userService.loadUserByUsername(username);
            List<RoleDTO> roles = customUser.getRoles();
            List<SimpleGrantedAuthority> authorities = new ArrayList<>();
            for(RoleDTO role: roles){
                SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.getRoleCode());
                authorities.add(authority);
            }
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(customUser, customUser.getPassword(), authorities);
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }


    /**
     * 打印请求头认证失败信息
     * @param response 响应体
     * @param status 响应码
     * @param message 响应消息
     * @throws IOException IO异常
     */
    private void printException(HttpServletResponse response, int status, String message) throws IOException {
        logger.error(message);
        response.setStatus(status);
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        PrintWriter printWriter = response.getWriter();
        RespBean<Void> responseResult = RespBean.error(status, message);
        printWriter.write(JSONObject.toJSONString(responseResult));
        printWriter.flush();
        printWriter.close();
    }
}
